/**
 * 教师考勤审批服务模块
 */

const { existsFlow, addAuditFlow, getList, updateAuditFlow, deleteAuditFlow, applyAttendance, searchMyAttendances, searchAuditApplies, canAuditAttendance, getAttendanceFlows, getLastFlowById, canAuditThisStep, getMaxStep, auditFlow, isMyLog, updateAttendanceFlow, getCouseTeacherIds, exChangeCourses, getAuditTeachers, getApplyIntersection } = require("../db/teacher_attendance_audit");
const { getUnavailableTeachers } = require('../db/teachers');
const { getIntersection, getCourseByIds } = require("../db/course_list");
const { AUDIT_STATUS, ATTENDANCE_TYPE } = require('../utils/CONST');
const dayjs = require('dayjs');

/**
 * 添加审批流
 * @param {*} ctx 
 */
const addFlow = async ctx => {
    try {
        const { attendance_id, steps } = ctx.request.body;
        const teacherIds = steps.map(c => c.teacher_id);  //拿到所有的步骤，并且去重
        const same = {};
        for (const teacher_id of teacherIds) {
            if (same[teacher_id]) {
                return ctx.body = {
                    code: 0,
                    msg: '请勿重复添加相同的教师'
                }
            }
            same[teacher_id] = true;
        }
        const flow = await existsFlow(attendance_id);
        if (flow) {
            return ctx.body = {
                code: 0,
                msg: '已存在相同的审批流程设置'
            }
        }
        const name = await getUnavailableTeachers(teacherIds);
        if (name) {
            return ctx.body = {
                code: 0,
                msg: name.name + '已离职，无法参与审批'
            }
        }
        const _steps = [...new Set(steps.map(c => c.step))];  //拿到所有的步骤，并且去重
        const max = Math.max(..._steps);
        for (let index = 1; index <= max; index++) {
            if (!_steps.some(c => c === index)) {
                return ctx.body = {
                    code: 0,
                    msg: `第${index}步不存在，请勿跳过此步骤`
                }
            }
        }
        steps.forEach(item => {
            item.attendance_id = attendance_id;
        });
        await addAuditFlow(steps);
        ctx.body = {
            code: 1,
            msg: '步骤添加成功'
        }
    } catch (error) {
        ctx.app.emit('error', error);
        ctx.body = {
            code: 0,
            msg: '审批流添加失败'
        }
    }
}


/**
 * 修改审批流
 * @param {*} ctx 
 */
const updateFlow = async ctx => {
    try {
        const { attendance_id, steps } = ctx.request.body;
        const teacherIds = steps.map(c => c.teacher_id);  //拿到所有的步骤，并且去重
        const same = {};
        for (const teacher_id of teacherIds) {
            if (same[teacher_id]) {
                return ctx.body = {
                    code: 0,
                    msg: '请勿重复添加相同的教师'
                }
            }
            same[teacher_id] = true;
        }
        const name = await getUnavailableTeachers(teacherIds);
        if (name) {
            return ctx.body = {
                code: 0,
                msg: name.name + '已离职，无法参与审批'
            }
        }
        const _steps = [...new Set(steps.map(c => c.step))];  //拿到所有的步骤，并且去重
        const max = Math.max(..._steps);
        for (let index = 1; index <= max; index++) {
            if (!_steps.some(c => c === index)) {
                return ctx.body = {
                    code: 0,
                    msg: `第${index}步不存在，请勿跳过此步骤`
                }
            }
        }
        steps.forEach(item => {
            item.attendance_id = attendance_id;
        });
        await updateAuditFlow(attendance_id, steps);
        ctx.body = {
            code: 1,
            msg: '步骤修改成功'
        }
    } catch (error) {
        ctx.app.emit('error', error);
        ctx.body = {
            code: 0,
            msg: '审批流修改失败'
        }
    }
}

/**
 * 获取审批列表
 * @param {*} ctx 
 */
const geAuditList = async ctx => {
    try {
        const data = await getList();
        ctx.body = {
            code: 1,
            data
        }
    } catch (error) {
        ctx.app.emit('error', error);
        ctx.body = {
            code: 0,
            msg: '审批列表获取失败'
        }
    }
}

/**
 * 删除审批流设置
 * @param {*} ctx 
 */
const deleteFlow = async ctx => {
    try {
        await deleteAuditFlow(ctx.request.params.type);
        ctx.body = {
            code: 1,
            msg: '审批流设置删除成功'
        }
    } catch (error) {
        ctx.app.emit('error', error);
        ctx.body = {
            code: 0,
            msg: '审批流设置删除失败'
        }
    }
}

/**
 * 申请考勤
 * @param {*} ctx 
 */
const apply = async ctx => {
    try {
        const body = ctx.request.body;
        const self = ctx.state.user.id;
        body.teacher_id = self;
        body.status_id = AUDIT_STATUS.Pending;
        const { attendance_id } = body;
        // 如果是请假或调休那么就需要判断是否和课程冲突
        if (attendance_id == ATTENDANCE_TYPE.请假 || attendance_id == ATTENDANCE_TYPE.调休) {
            const { from_date, end_date } = body;
            const from = new Date(from_date);
            const end = new Date(end_date);
            if (from >= end) {
                return ctx.body = {
                    code: 0,
                    msg: '开始时间不得大于等于结束时间'
                }
            }
            if (from <= new Date()) {
                return ctx.body = {
                    code: 0,
                    msg: '开始时间不得小于等于当前时间'
                }
            }
            let intersection = await getIntersection({ ...body, class_id: 0 });
            if (intersection) {
                const { from_date: f, end_date: e } = intersection;
                return ctx.body = {
                    code: 0,
                    msg: `您在${dayjs(f).format('YYYY-MM-DD HH:mm:ss')}至${dayjs(e).format('YYYY-MM-DD HH:mm:ss')}有课程，无法提交申请`
                }
            }
            intersection = await getApplyIntersection(self, from_date, end_date);
            if (intersection) {
                const { from_date: f, end_date: e } = intersection;
                return ctx.body = {
                    code: 0,
                    msg: `您在${dayjs(f).format('YYYY-MM-DD HH:mm:ss')}至${dayjs(e).format('YYYY-MM-DD HH:mm:ss')}有考勤申请，无法再次申请`
                }
            }
        } else {
            const { from_course_id, to_course_id } = body;
            if (from_course_id === to_course_id) {
                return ctx.body = {
                    code: 0,
                    msg: '相同的课程无需调课'
                }
            }
            //如果是调课则判断两个课程是否都存在
            const courses = await getCourseByIds([from_course_id, to_course_id]);
            if (courses.length < 2) {
                return ctx.body = {
                    code: 0,
                    msg: '课程不存在，请勿非法操作'
                }
            }
            const from = courses.find(c => c.id == from_course_id);
            const to = courses.find(c => c.id == to_course_id);
            if (from.teacher_id != self) {
                return ctx.body = {
                    code: 0,
                    msg: '不是自己的课，不能调课'
                }
            }
            if (to.teacher_id == self) {
                return ctx.body = {
                    code: 0,
                    msg: '都是自己的课，无需调整'
                }
            }
            const { from_date: f } = from;
            if (new Date(f) <= new Date()) {
                return ctx.body = {
                    code: 0,
                    msg: '您的课程已开始或结束，无法调课'
                }
            }
            const { from_date, end_date } = to;
            if (new Date(from_date) <= new Date()) {
                return ctx.body = {
                    code: 0,
                    msg: '对方的课程已开始或结束，无法调课'
                }
            }
            const intersection = await getIntersection({ ...body, class_id: 0, from_date, end_date });
            if (intersection) {
                const { from_date: f, end_date: e } = intersection;
                return ctx.body = {
                    code: 0,
                    msg: `您在${dayjs(f).format('YYYY-MM-DD HH:mm:ss')}至${dayjs(e).format('YYYY-MM-DD HH:mm:ss')}有课程，无法提交申请`
                }
            }
        }
        await applyAttendance(body, { attendance_id, step: 1, status_id: AUDIT_STATUS.Pending });
        ctx.body = {
            code: 1,
            msg: '考勤申请成功'
        }
    } catch (error) {
        ctx.app.emit('error', error);
        ctx.body = {
            code: 0,
            msg: '考勤申请失败'
        }
    }
}

/**
 * 搜索我的考勤列表
 * @param {*} ctx 
 */
const searchMyAttendanceList = async ctx => {
    try {
        const obj = ctx.request.query;
        obj.teacher_id = ctx.state.user.id;
        const [data, total] = await searchMyAttendances(ctx.request.query);
        ctx.body = {
            code: 1,
            data,
            total
        }
    } catch (error) {
        ctx.app.emit('error', error);
        ctx.body = {
            code: 0,
            msg: '考勤列表搜索失败'
        }
    }
}

/**
 * 搜索需要审批的申请
 * @param {*} ctx 
 */
const searchNeedAuditApplies = async ctx => {
    try {
        const data = await searchAuditApplies(ctx.state.user.id);
        ctx.body = {
            code: 1,
            data,
        }
    } catch (error) {
        ctx.app.emit('error', error);
        ctx.body = {
            code: 0,
            msg: '审批单据搜索失败'
        }
    }
}

/**
 * 获取审批流
 * @param {*} ctx 
 */
const getFlows = async ctx => {
    try {
        const { id: teacher_id } = ctx.state.user;
        const { id } = ctx.request.params;
        const teachers = await getAuditTeachers(id);
        if (!teachers.some(c => c.teacher_id === teacher_id)) {
            return ctx.body = {
                code: 0,
                msg: '您无权限审批此考勤'
            }
        }
        const data = await getAttendanceFlows(id);
        ctx.body = {
            code: 1,
            data,
        }
    } catch (error) {
        ctx.app.emit('error', error);
        ctx.body = {
            code: 0,
            msg: '审批流获取失败'
        }
    }
}

/**
 * 获取我的审批流
 * @param {*} ctx 
 */
const getMyFlows = async ctx => {
    try {
        const { id: teacher_id } = ctx.state.user;
        const { id } = ctx.request.params;
        const obj = await isMyLog(id, teacher_id);
        if (!obj) {
            return ctx.body = {
                code: 0,
                msg: '此申请不是您的，请勿非法操作'
            }
        }
        const data = await getAttendanceFlows(id);
        const last = data[data.length - 1];
        if (last.status_id == AUDIT_STATUS.Pending) {
            const teachers = await getAuditTeachers(id);
            last.auditors = teachers;
        }
        ctx.body = {
            code: 1,
            data,
        }
    } catch (error) {
        ctx.app.emit('error', error);
        ctx.body = {
            code: 0,
            msg: '审批流获取失败'
        }
    }
}

/**
 * 审批
 * @param {*} ctx 
 */
const audit = async ctx => {
    try {
        const { id: teacher_id } = ctx.state.user;
        const { id, status_id, message } = ctx.request.body;
        const flow = await getLastFlowById(id); //获取最后一个审批流
        if (!flow) {
            return ctx.body = {
                code: 0,
                msg: '此考勤不存在，请勿非法操作'
            }
        }
        let { status_id: status, attendance_id, step, id: flowId } = flow;
        if (status !== AUDIT_STATUS.Pending) {
            return ctx.body = {
                code: 0,
                msg: '此考勤目前不是待审批状态'
            }
        }
        const can = await canAuditThisStep(attendance_id, step, teacher_id);
        if (!can) {
            return ctx.body = {
                code: 0,
                msg: '您无权限审批此步骤'
            }
        }
        if (status_id == AUDIT_STATUS.Back) {
            step = Math.max(step - 1, 1);
        }
        else if (status_id == AUDIT_STATUS.Success) {
            const { step: s } = await getMaxStep(attendance_id);
            if (step >= s) {
                step = undefined
            }
        }
        await auditFlow({ status_id, attendance_id, teacher_attendance_id: id, step, id: flowId, audit_id: teacher_id, auditMessage: message });
        //如果是成功，并且没有下一步，就是审批通过了
        if (status_id == AUDIT_STATUS.Success && !step) {
            // 如果是调课
            if (attendance_id == 35) {
                const { from_course_id, to_course_id, ffrom_date, fend_date, efrom_date, eend_date } = await getCouseTeacherIds(id);
                await exChangeCourses(from_course_id, to_course_id, efrom_date, eend_date, ffrom_date, fend_date);
            }
        }
        ctx.body = {
            code: 1,
            msg: '审批成功'
        }
    } catch (error) {
        ctx.app.emit('error', error);
        ctx.body = {
            code: 0,
            msg: '审批失败'
        }
    }
}

/**
 * 更新我的审批流
 * @param {*} ctx 
 */
const updateMyFlow = async ctx => {
    try {
        const { id: teacher_id } = ctx.state.user;
        const obj = ctx.request.body;
        const { id } = obj;
        const my = await isMyLog(id, teacher_id);
        if (!my) {
            return ctx.body = {
                code: 0,
                msg: '此申请不是您的考勤，请勿非法操作'
            }
        }
        const { id: flowId, status_id } = await getLastFlowById(id);
        if (![36, 40].includes(status_id)) {
            return ctx.body = {
                code: 0,
                msg: '此考勤不是审批中和待补充状态，无法操作'
            }
        }
        await updateAttendanceFlow({ ...obj, flowId });
        ctx.body = {
            code: 1,
            msg: '提交成功'
        }
    } catch (error) {
        ctx.app.emit('error', error);
        ctx.body = {
            code: 0,
            msg: '提交失败'
        }
    }
}

module.exports = {
    audit,
    apply,
    addFlow,
    getFlows,
    updateFlow,
    getMyFlows,
    deleteFlow,
    geAuditList,
    updateMyFlow,
    searchMyAttendanceList,
    searchNeedAuditApplies
}